package com.life.ai.server.modules.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.life.ai.server.common.domain.PageQuery;
import com.life.ai.server.common.exception.ServiceException;
import com.life.ai.server.modules.system.entity.SysMenu;
import com.life.ai.server.modules.system.entity.SysRoleMenu;
import com.life.ai.server.modules.system.enums.MenuStatusEnum;
import com.life.ai.server.modules.system.enums.MenuVisibleEnum;
import com.life.ai.server.modules.system.mapper.SysMenuMapper;
import com.life.ai.server.modules.system.model.vo.SysMenuNodeVO;
import com.life.ai.server.modules.system.service.SysMenuService;
import com.life.ai.server.modules.system.service.SysRoleMenuService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单权限 服务实现类
 * </p>
 *
 * @author kylewka
 * @since 2024-06-11
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    @Resource
    private SysRoleMenuService roleMenuService;

    /**
     * 构建分页和列表的通用查询条件
     *
     * @param menu 角色信息
     * @return queryWrapper
     */
    private QueryWrapper<SysMenu> queryWrapper(SysMenu menu) {
        QueryWrapper<SysMenu> querywrapper = new QueryWrapper<>();
        querywrapper.lambda().like(StrUtil.isNotBlank(menu.getMenuName()), SysMenu::getMenuName, menu.getMenuName())
                .eq(StrUtil.isNotBlank(menu.getVisible()), SysMenu::getVisible, menu.getVisible())
                .eq(StrUtil.isNotBlank(menu.getStatus()), SysMenu::getStatus, menu.getStatus())
                .orderByAsc(SysMenu::getSort);
        return querywrapper;
    }

    /**
     * 分页查询
     *
     * @param pageQuery 分页参数
     * @param sysMenu 查询条件
     * @return Page<SysMenu>
     */
    @Override
    public Page<SysMenu> selectMenuPage(PageQuery pageQuery, SysMenu sysMenu){
        return page(pageQuery.build(), queryWrapper(sysMenu));
    }

    /**
     * 查询系统菜单列表
     *
     * @param menu 菜单信息
     * @return 菜单列表
     */
    @Override
    public List<SysMenu> selectMenuList(SysMenu menu) {
        return list(queryWrapper(menu));
    }

    /**
     * 查询系统菜单列表（树形）
     *
     * @param menu 菜单信息
     * @return 菜单列表
     */
    @Override
    public List<SysMenuNodeVO> selectMenuTree(SysMenu menu) {
        List<SysMenu> sysMenus = selectMenuList(menu);
        return sysMenus.stream().filter(sysMenu -> Objects.equals(sysMenu.getParentId(), 0L))
                .map(sysMenu -> covertMenuNode(sysMenu, sysMenus)).collect(Collectors.toList());
    }

    /**
     * 将SysMenu转化为SysMenuNode并设置children属性
     */
    private SysMenuNodeVO covertMenuNode(SysMenu sysMenu, List<SysMenu> menus) {
        SysMenuNodeVO sysMenuNode = BeanUtil.copyProperties(sysMenu, SysMenuNodeVO.class);
        List<SysMenuNodeVO> children = menus.stream()
                .filter(menu -> Objects.equals(menu.getParentId(), (sysMenuNode.getId())))
                .map(menu -> covertMenuNode(menu.addParentMenus(sysMenu), menus)).collect(Collectors.toList());
        sysMenuNode.setChildren(CollUtil.isNotEmpty(children) ? children : null);
        return sysMenuNode;
    }

    /**
     * 新增菜单
     *
     * @param menu 菜单信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addMenu(SysMenu menu) {
        // 校验菜单名称是否唯一
        if (checkMenuNameUnique(menu)) {
            throw new ServiceException("新增菜单失败，菜单名[{}]已存在", menu.getMenuName());
        }
        // 设置菜单默认值
        menu.setVisible(Objects.isNull(menu.getVisible()) ? MenuVisibleEnum.VISIBLE.getCode() : menu.getVisible());
        menu.setStatus(Objects.isNull(menu.getStatus()) ? MenuStatusEnum.ENABLE.getCode() : menu.getStatus());
        this.save(menu);
    }

    /**
     * 编辑菜单
     *
     * @param menu 菜单信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateMenu(SysMenu menu) {
        // 校验菜单名称是否唯一
        if (checkMenuNameUnique(menu)) {
            throw new ServiceException("新增菜单失败，菜单名[{}]已存在", menu.getMenuName());
        } else if (menu.getId().equals(menu.getParentId())) {
            throw new ServiceException("修改菜单[{}]失败，上级菜单不能选择自己", menu.getMenuName());
        }
        this.updateById(menu);
    }


    /**
     * 删除菜单管理信息
     *
     * @param id 菜单ID
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteMenuById(Long id) {
        if (hasChildByMenuId(id)) {
            throw new ServiceException("存在子菜单,不允许删除");
        }
        if (checkMenuExistRole(id)) {
            throw new ServiceException("菜单已分配,不允许删除");
        }
        this.removeById(id);
    }

    /**
     * 校验菜单名称是否唯一
     *
     * @param menu 菜单信息
     * @return 结果
     */
    private boolean checkMenuNameUnique(SysMenu menu) {
        return lambdaQuery().eq(SysMenu::getMenuName, menu.getMenuName())
                .eq(SysMenu::getParentId, menu.getParentId())
                .ne(ObjectUtil.isNotNull(menu.getId()), SysMenu::getId, menu.getId()).exists();
    }

    /**
     * 是否存在菜单子节点
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    private boolean hasChildByMenuId(Long menuId) {
        return lambdaQuery().eq(SysMenu::getParentId, menuId).exists();
    }

    /**
     * 是否已有角色使用菜单
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    private boolean checkMenuExistRole(Long menuId) {
        return roleMenuService.lambdaQuery().eq(SysRoleMenu::getMenuId, menuId).exists();
    }
}

